<?php
declare(strict_types=1);
namespace qhweb\phpsm\ecc\sm2;

use Mdanter\Ecc\Curves\NamedCurveFp;
use Mdanter\Ecc\Math\GmpMathInterface;
use Mdanter\Ecc\Primitives\CurveParameters;
use Mdanter\Ecc\Primitives\GeneratorPoint;
use Mdanter\Ecc\Random\RandomNumberGeneratorInterface;

/**
 * 国密 SM2 椭圆曲线定义类
 *
 * 本类用于定义和生成符合中国国家密码管理局标准 GM/T 0003-2012 的 SM2 椭圆曲线参数，
 * 包括曲线本身（NamedCurveFp）及其对应的基准生成点（GeneratorPoint）。
 * 该曲线通常用于 SM2 数字签名、密钥交换等密码学方案。
 *
 * 基于 Mdanter\Ecc 库构建，使用 GMP 大整数运算。
 */
class Sm2Curve
{
    //曲线名称常量，标识为 SM2
    const NAME_PSM2 = 'SM2';
    /**
     * 数学运算适配器（基于 GMP）
     * 提供大整数运算、模运算等基础数学操作，由外部传入。
     * @var GmpMathInterface
     */
    private $adapter;

    /**
     * 构造方法
     *
     * @param GmpMathInterface $adapter 数学运算适配器实例，用于所有大数运算
     */
    public function __construct(GmpMathInterface $adapter)
    {
        $this->adapter = $adapter;
        // echo "I am sm ecc\n";
    }
    /**
     * 获取 SM2 标准椭圆曲线对象
     *
     * 构造并返回一个符合 GM/T 0003-2012 标准的命名椭圆曲线（NamedCurveFp），
     * 包含曲线参数：素数 p、系数 a、系数 b，以及曲线位数 256。
     *
     * @return NamedCurveFp 符合 SM2 标准的椭圆曲线对象
     */
    public function curveSm2(): NamedCurveFp
    {
        // SM2 曲线参数（十六进制，大端）
        $p = gmp_init('0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16);
        $b = gmp_init('0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', 16);
        $a = gmp_init('0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 16);

        // 构造曲线参数对象
        $parameters = new CurveParameters(256, $p, $a, $b);

        // 返回命名曲线对象，标识为 'SM2'
        return new NamedCurveFp(self::NAME_PSM2, $parameters, $this->adapter);
    }

     /**
     * 获取 SM2 标准椭圆曲线的生成点（基准点 G）
     *
     * 生成并返回 SM2 曲线的基准生成点（GeneratorPoint），即椭圆曲线上的一个固定点，
     * 用于密钥生成、签名等操作。该点坐标 (x, y) 与阶数 order 均符合 GM/T 0003-2012 标准。
     *
     * @param  RandomNumberGeneratorInterface|null $randomGenerator 可选的随机数生成器（一般用于某些库内部扩展，SM2 基准点通常固定，可传 null）
     * @return GeneratorPoint                      SM2 曲线的基准生成点对象
     */
    public function generatorSm2(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint
    {
        $curve = $this->curveSm2();
        $order = gmp_init('0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 16);

        $x = gmp_init('0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7', 16);
        $y = gmp_init('0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0', 16);

        return $curve->getGenerator($x, $y, $order, $randomGenerator);
    }
}